using System;
using System.IO;
using Icinetic.FeedCategorySample.CrossCutting;
using Icinetic.FeedCategorySample.Entities;

namespace Icinetic.FeedCategorySample.Services.Repositories
{
    public abstract class BaseRepository
    {
        private int TimeOut = 50;
        public static string DbPath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "FeedCategorySample.db");

        public BaseRepository()
        {
        }

        public static void Initialize()
        {
            LoggingService.Log("Service.Initialize(): Creating SQLite database if necessary");

            using (var db = new SQLite.SQLiteConnection(DbPath))
            {
                db.CreateTable<RssItem>();
            }

            LoggingService.Log("Service.Initialize() finalized");
        }

        protected void ExecuteWithRetry(Action sentences, OperationType operationType, int maxRetries = 50)
        {
            ExecuteWithRetry<int>(() => { sentences(); return 1; }, operationType, maxRetries);
        }

        protected T ExecuteWithRetry<T>(Func<T> sentences, OperationType operationType, int maxRetries = 50)
        {
            int currentTries = 0;
            T result = default(T);

            do
            {
                try
                {
                    result = sentences();
                    break;
                }
                catch (SQLite.SQLiteException ex)
                {
                    if (ex.Result == SQLite.SQLite3.Result.Busy)
                    {
                        LoggingService.Log("Database is BUSY", ex);
                    }
                    else if (ex.Result == SQLite.SQLite3.Result.Locked)
                    {
                        LoggingService.Log("Database is LOCKED", ex);
                    }
                    else
                    {
                        LoggingService.Log("Database operation not completed", ex);
                    }

                    currentTries++;
                }
                TimeOut = operationType == OperationType.Read ? 10 : 100;

                new System.Threading.ManualResetEvent(false).WaitOne(TimeOut);
            }
            while (currentTries <= maxRetries);

            return result;
        }

        public enum OperationType
        {
            Write,
            Read
        }
    }
}
